/*
 * LvTimer.h
 *
 */

#ifndef LVTIMER_H_
#define LVTIMER_H_

#include "../core/lvglpp.h"

namespace lvglpp
{

	class LvTimer : public lv_timer_t
	{
	private:
		LvTimer() = default;

	public:
		lv_timer_t *raw() noexcept { return this; }

		/**
		 * Create an "empty" timer. It needs to initialized with at least
		 * `lv_timer_set_cb` and `lv_timer_set_period`
		 * @return pointer to the created timer
		 */
		static inline LvTimer *create() noexcept
		{
			static_assert(sizeof(LvTimer) == sizeof(lv_timer_t));
			return (LvTimer *)lv_timer_create_basic();
		}

		/**
		 * Create a new lv_timer
		 * @param timer_xcb a callback to call periodically.
		 *                 (the 'x' in the argument name indicates that it's not a fully generic function because it not follows
		 *                  the `func_name(object, callback, ...)` convention)
		 * @param period call period in ms unit
		 * @param user_data custom parameter
		 * @return pointer to the new timer
		 */
		static inline LvTimer *create(lv_timer_cb_t timer_xcb, uint32_t period, void *user_data) noexcept
		{
			static_assert(sizeof(LvTimer) == sizeof(lv_timer_t));
			return (LvTimer *)lv_timer_create(timer_xcb, period, user_data);
		}

		static inline LvPointer<LvTimer, lv_timer_del> Make() noexcept { return LvPointer<LvTimer, lv_timer_del>{create()}; }
		static inline LvPointer<LvTimer, lv_timer_del> Make(lv_timer_cb_t timer_xcb, uint32_t period, void *user_data) noexcept { return LvPointer<LvTimer, lv_timer_del>{create(timer_xcb, period, user_data)}; }

		/**
		 * Enable or disable the whole lv_timer handling
		 * @param en true: lv_timer handling is running, false: lv_timer handling is suspended
		 */
		static inline void enable(bool en) noexcept { lv_timer_enable(en); }

		/**
		 * Get idle percentage
		 * @return the lv_timer idle in percentage
		 */
		static inline uint8_t getIdle(void) noexcept { return lv_timer_get_idle(); }

	public:
		/**
		 * Delete a lv_timer
		 * @param timer pointer to an lv_timer
		 */
		inline LvTimer &del() noexcept { return lv_timer_del(raw()), *this; }

		/**
		 * Pause/resume a timer.
		 * @param timer pointer to an lv_timer
		 */
		inline LvTimer &pause() noexcept { return lv_timer_pause(raw()), *this; }

		inline LvTimer &resume() noexcept { return lv_timer_resume(raw()), *this; }

		/**
		 * Set the callback the timer (the function to call periodically)
		 * @param timer pointer to a timer
		 * @param timer_cb the function to call periodically
		 */
		inline LvTimer &setCb(lv_timer_cb_t timer_cb) noexcept { return lv_timer_set_cb(raw(), timer_cb), *this; }

		/**
		 * Set new period for a lv_timer
		 * @param timer pointer to a lv_timer
		 * @param period the new period
		 */
		inline LvTimer &setPeriod(uint32_t period) noexcept { return lv_timer_set_period(raw(), period), *this; }

		/**
		 * Make a lv_timer ready. It will not wait its period.
		 * @param timer pointer to a lv_timer.
		 */
		inline LvTimer &ready() noexcept { return lv_timer_ready(raw()), *this; }

		/**
		 * Set the number of times a timer will repeat.
		 * @param timer pointer to a lv_timer.
		 * @param repeat_count -1 : infinity;  0 : stop ;  n>0: residual times
		 */
		inline LvTimer &setRepeatCount(int32_t repeat_count) noexcept { return lv_timer_set_repeat_count(raw(), repeat_count), *this; }

		/**
		 * Reset a lv_timer.
		 * It will be called the previously set period milliseconds later.
		 * @param timer pointer to a lv_timer.
		 */
		inline LvTimer &reset() noexcept { return lv_timer_reset(raw()), *this; }

		/**
		 * Iterate through the timers
		 * @param timer NULL to start iteration or the previous return value to get the next timer
		 * @return the next timer or NULL if there is no more timer
		 */
		inline LvTimer *getNext() noexcept { return (LvTimer *)lv_timer_get_next(raw()); }
	};

} /* namespace lvglpp */

#endif /* LVTIMER_H_ */
